package ru.averta.notes.service.search;

import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

/**
 * <code>MistakeLettersDetector</code>
 *
 * @author fedor.belov (fedor.belov@mail.ru)
 *         Date: 09.09.11 19:59
 */

@Service
public class MistakeLettersDetector {

    Map<String, char[]> mistakeLetters = new HashMap<String, char[]>();

    @PostConstruct
    public void setUp() {
        //Формируем карту похожих букв, в которых пользователь может совершить ошибки
        loadMistakeLetters(new char[] {'a', 'e', 'i', 'o', 'u', 'y'});
        loadMistakeLetters(new char[] {'b', 'p'});
        loadMistakeLetters(new char[] {'c', 'k', 'q'});
        loadMistakeLetters(new char[] {'d', 't'});
        loadMistakeLetters(new char[] {'l', 'r'});
        loadMistakeLetters(new char[] {'m', 'n'});
        loadMistakeLetters(new char[] {'g', 'j'});
        loadMistakeLetters(new char[] {'f', 'v'});
        loadMistakeLetters(new char[] {'s', 'x', 'z'});
        loadMistakeLetters(new char[] {'s', 'z'});

        //Русские буквы
        loadMistakeLetters(new char[] {'а', 'о'});
        loadMistakeLetters(new char[] {'е', 'и'});
        loadMistakeLetters(new char[] {'з', 'с'});
        loadMistakeLetters(new char[] {'у', 'ю'});
    }

    /**
     * Возвращает true, если буквы входят в общую фонетическу группу
     * (похожи / существует вероятность ошибки)
     *
     * @param first
     * @param second
     * @return
     */
    public boolean isMistakeLetters(char first, char second) {
        char[] letters = mistakeLetters.get(String.valueOf(first));
        return (letters != null && containsLetter(letters, second));
    }

    /**
     * Загружает буквы с общей фонетической группой, чтобы их потом было просто найти
     *
     * @param letters
     */
    private void loadMistakeLetters(char[] letters) {
        for (char letter : letters) {
            String strLetter = String.valueOf(letter);
            char[] lettersOld = mistakeLetters.get(strLetter);
            char[] lettersNew;

            if (lettersOld == null) {
                lettersNew = new char[letters.length];
            } else {
                lettersNew = new char[letters.length + lettersOld.length];
            }

            //Максимально оптимизируем данные в момент создания сервиса.
            //Из конечного массива удаляем повторяющиеся буквы
            int j = 0;
            for (int i = 0; i < letters.length; i++) {
                if (letters[i] != letter && !containsLetter(lettersNew, letters[i])) {
                    lettersNew[j] = letters[i];
                    j++;
                }
                ;
            }

            if (lettersOld != null) {
                for (int i = 0; i < lettersOld.length; i++) {
                    if (lettersOld[i] != letter && !containsLetter(lettersNew, lettersOld[i])) {
                        lettersNew[j] = lettersOld[i];
                        j++;
                    }
                }
            }

            //"Укорачиваем массив"
            char[] lettersFinal = new char[j];
            for (int i = 0; i < j; i++) lettersFinal[i] = lettersNew[i];
            mistakeLetters.put(strLetter, lettersFinal);
        }
    }

    /**
     * Возвращает true, если в массиве хранится буква
     *
     * @param letters
     * @param letterToFind
     * @return
     */
    private boolean containsLetter(char[] letters, char letterToFind) {
        for (int i=0; i<letters.length; i++) {
            if (letters[i] == letterToFind) return true;
        }

        return false;
    }

}
